const { Subject, Observer, ConcreteObserver } = require("./template.js")

function testObserverPattern() {
  console.log("=== 观察者模式测试 ===")

  console.log(
    "1. 基本观察者功能:",
    (() => {
      const subject = new Subject()
      const observer = new ConcreteObserver("Observer1")

      subject.addObserver(observer)
      subject.notify("test data")

      return observer.getReceivedData() === "test data"
    })()
  )

  console.log(
    "2. 多个观察者:",
    (() => {
      const subject = new Subject()
      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      subject.addObserver(observer1)
      subject.addObserver(observer2)
      subject.notify("multi data")

      return (
        observer1.getReceivedData() === "multi data" &&
        observer2.getReceivedData() === "multi data"
      )
    })()
  )

  console.log(
    "3. 移除观察者:",
    (() => {
      const subject = new Subject()
      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      subject.addObserver(observer1)
      subject.addObserver(observer2)
      subject.removeObserver(observer1)
      subject.notify("remove test")

      return (
        observer1.getReceivedData() === null &&
        observer2.getReceivedData() === "remove test"
      )
    })()
  )

  console.log(
    "4. 观察者数量统计:",
    (() => {
      const subject = new Subject()
      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      subject.addObserver(observer1)
      subject.addObserver(observer2)

      return subject.getObserverCount() === 2
    })()
  )

  console.log(
    "5. 重复添加观察者:",
    (() => {
      const subject = new Subject()
      const observer = new ConcreteObserver("Observer1")

      subject.addObserver(observer)
      subject.addObserver(observer) // 重复添加

      return subject.getObserverCount() === 1
    })()
  )

  console.log(
    "6. 移除不存在的观察者:",
    (() => {
      const subject = new Subject()
      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      subject.addObserver(observer1)
      subject.removeObserver(observer2) // 移除不存在的观察者

      return subject.getObserverCount() === 1
    })()
  )

  console.log(
    "7. 空观察者列表通知:",
    (() => {
      const subject = new Subject()

      // 没有观察者时通知不应该报错
      try {
        subject.notify("empty test")
        return true
      } catch (e) {
        return false
      }
    })()
  )

  console.log(
    "8. 观察者更新顺序:",
    (() => {
      const subject = new Subject()
      const updates = []

      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      // 重写update方法来记录更新顺序
      observer1.update = function (data) {
        updates.push("Observer1")
      }
      observer2.update = function (data) {
        updates.push("Observer2")
      }

      subject.addObserver(observer1)
      subject.addObserver(observer2)
      subject.notify("order test")

      return updates.length === 2
    })()
  )

  console.log(
    "9. 复杂数据通知:",
    (() => {
      const subject = new Subject()
      const observer = new ConcreteObserver("Observer1")

      const complexData = {
        id: 1,
        name: "test",
        data: [1, 2, 3]
      }

      subject.addObserver(observer)
      subject.notify(complexData)

      const receivedData = observer.getReceivedData()
      return (
        receivedData &&
        receivedData.id === 1 &&
        receivedData.name === "test" &&
        Array.isArray(receivedData.data)
      )
    })()
  )

  console.log(
    "10. 观察者链式操作:",
    (() => {
      const subject = new Subject()
      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      subject.addObserver(observer1).addObserver(observer2).notify("chain test")

      return (
        observer1.getReceivedData() === "chain test" &&
        observer2.getReceivedData() === "chain test"
      )
    })()
  )

  console.log(
    "11. 观察者错误处理:",
    (() => {
      const subject = new Subject()
      const observer1 = new ConcreteObserver("Observer1")
      const observer2 = new ConcreteObserver("Observer2")

      // 让一个观察者抛出错误
      observer1.update = function (data) {
        throw new Error("Observer error")
      }

      subject.addObserver(observer1)
      subject.addObserver(observer2)

      try {
        subject.notify("error test")
        // 即使一个观察者出错，其他观察者仍应该收到通知
        return observer2.getReceivedData() === "error test"
      } catch (e) {
        return false
      }
    })()
  )

  console.log(
    "12. 观察者模式实际应用:",
    (() => {
      // 模拟新闻发布系统
      const newsSubject = new Subject()
      const emailObserver = new ConcreteObserver("Email")
      const smsObserver = new ConcreteObserver("SMS")

      newsSubject.addObserver(emailObserver)
      newsSubject.addObserver(smsObserver)

      const news = {
        title: "Breaking News",
        content: "Important update",
        timestamp: new Date()
      }

      newsSubject.notify(news)

      return (
        emailObserver.getReceivedData() &&
        smsObserver.getReceivedData() &&
        emailObserver.getReceivedData().title === "Breaking News"
      )
    })()
  )

  console.log(
    "13. this上下文测试:",
    (() => {
      const obj = {
        prefix: "observer_",
        createObserver: function(name) {
          const observer = new ConcreteObserver(this.prefix + name)
          return observer.name === this.prefix + name
        }
      }
      return obj.createObserver("test")
    })()
  )

  console.log(
    "14. 方法调用this绑定:",
    (() => {
      const obj = {
        multiplier: 3,
        createSubject: function() {
          const subject = new Subject()
          const observer = new ConcreteObserver("test")
          subject.addObserver(observer)
          subject.notify(this.multiplier * 2)
          return observer.getReceivedData() === 6
        }
      }
      return obj.createSubject()
    })()
  )

  console.log(
    "15. 复杂对象this绑定:",
    (() => {
      const obj = {
        config: { observerCount: 2 },
        createConfigObservers: function() {
          const subject = new Subject()
          const observers = []
          for (let i = 0; i < this.config.observerCount; i++) {
            observers.push(new ConcreteObserver(`Observer${i}`))
            subject.addObserver(observers[i])
          }
          return subject.getObserverCount() === this.config.observerCount
        }
      }
      return obj.createConfigObservers()
    })()
  )
}

testObserverPattern()
